﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

using SouthApps.MobileHealth.SDK.DAL.Model;
using SouthApps.MobileTasks.SDK.DAL.Repositories;
using SouthApps.Framework.LoggerService;

namespace SouthApps.MobileHealth.SDK.Cache
{
    public static class GuardiasSucursalPrestadorCache
    {
        private static ReaderWriterLock cacheReaderWriterLock = new ReaderWriterLock();
        private static IPrestadoresRepository prestadoresRepository;
        private static Dictionary<int, List<GuardiaSucursalPrestador>> guardiasSucursalesPrestadoresFinanciador = new Dictionary<int, List<GuardiaSucursalPrestador>>();
        private static bool initialized = false;
        private static object lockObject = new object();

        public static void Initialize(List<int> financiadoresId)
        {
            try
            {
                lock (lockObject)
                {
                    if (!initialized)
                    {
                        GuardiasSucursalPrestadorCache.prestadoresRepository = new PrestadoresRepository();
                        GuardiasSucursalPrestadorCache.LoadGuardiasSucursalPrestadorFromDatabase(financiadoresId);
                        initialized = true;
                    }
                }
            }
            catch (Exception ex)
            {
                LoggerService.Log(LogLevel.Error, "An error ocurred while initializing guardias sucursales prestador cache.", ex);
                throw ex;
            }
        }

        private static void LoadGuardiasSucursalPrestadorFromDatabase(List<int> financiadoresId)
        {
            cacheReaderWriterLock.AcquireWriterLock(Timeout.Infinite);

            try
            {
                foreach (int financiadorId in financiadoresId)
                {
                    List<GuardiaSucursalPrestador> guardiasSucursalesPrestador = GuardiasSucursalPrestadorCache.prestadoresRepository.GetGuardiasSucursalesPrestador(financiadorId);
                    GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador.Add(financiadorId, guardiasSucursalesPrestador);
                }
            }
            finally
            {
                cacheReaderWriterLock.ReleaseWriterLock();
            }
        }

        public static void AddGuardiaSucursalPrestadorToCache(int financiadorId, GuardiaSucursalPrestador sucursalPrestador)
        {
            cacheReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            if (GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador.ContainsKey(financiadorId))
            {
                List<GuardiaSucursalPrestador> guardiasSucursalPrestadorList = GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador[financiadorId];

                cacheReaderWriterLock.UpgradeToWriterLock(Timeout.Infinite);
                guardiasSucursalPrestadorList.Add(sucursalPrestador);
                GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador[financiadorId] = guardiasSucursalPrestadorList;

                cacheReaderWriterLock.ReleaseLock();
            }
            else
            {
                List<GuardiaSucursalPrestador> guardiasSucursalPrestadorList = new List<GuardiaSucursalPrestador>();
                guardiasSucursalPrestadorList.Add(sucursalPrestador);

                cacheReaderWriterLock.UpgradeToWriterLock(Timeout.Infinite);
                GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador.Add(financiadorId, guardiasSucursalPrestadorList);

                cacheReaderWriterLock.ReleaseLock();
            }
        }

        public static void RemoveGuardiaSucursalPrestadorFromCache(int financiadorId, GuardiaSucursalPrestador sucursalPrestador)
        {
            cacheReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            if (!GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador.ContainsKey(financiadorId))
                return;

            List<GuardiaSucursalPrestador> guardiasSucursalPrestadorList = GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador[financiadorId];

            cacheReaderWriterLock.UpgradeToWriterLock(Timeout.Infinite);
            guardiasSucursalPrestadorList.Remove(sucursalPrestador);
            GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador[financiadorId] = guardiasSucursalPrestadorList;

            cacheReaderWriterLock.ReleaseLock();
        }

        public static void UpdateGuardiaSucursalPrestadorToCache(int financiadorId, GuardiaSucursalPrestador sucursalPrestador)
        {
            cacheReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            if (!GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador.ContainsKey(financiadorId))
                return;

            List<GuardiaSucursalPrestador> guardiasSucursalPrestadorList = GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador[financiadorId];
            //TODO: terminar
        }

        public static List<GuardiaSucursalPrestador> GetGuardiasSucursalesPrestador(int financiadorId, int? servicioGuardiaId)
        {
            return GuardiasSucursalPrestadorCache.GetGuardiasSucursalesPrestador(financiadorId, servicioGuardiaId, null);
        }

        public static List<GuardiaSucursalPrestador> GetGuardiasSucursalesPrestador(int financiadorId, int? servicioGuardiaId, int? departamentoId)
        {
            cacheReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            try
            {
                if (!GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador.ContainsKey(financiadorId))
                    return new List<GuardiaSucursalPrestador>();

                var guardiasSucursalesPrestador = from guardiaSucursalPrestador in GuardiasSucursalPrestadorCache.guardiasSucursalesPrestadoresFinanciador[financiadorId]
                                             where ((departamentoId == null || guardiaSucursalPrestador.sucursalprestador.departamentoId == departamentoId) 
                                             && (servicioGuardiaId == null || guardiaSucursalPrestador.servicioGuardiaId == servicioGuardiaId))
                                             select guardiaSucursalPrestador;

                return guardiasSucursalesPrestador.ToList();
            }
            finally
            {
                cacheReaderWriterLock.ReleaseReaderLock();
            }
        }
    }
}
